/*
 * MathBoard.cpp
 *
 *  Created on: 2011-6-10
 *      Author: rs
 */
#include "MathBoard.h"

MathBoard::MathBoard(const RegionBoard& board){
	memset(influence, 0, sizeof(influence));
	for (SgVectorIteratorOf<Region> it(board.getAllRegions(SG_BLACK)); it; ++it) {
		Region* region = *it;
		if (!board.isDead(*region)){
			SgPointSet points = region->area();
			for (SgSetIterator point(points); point; ++point)
				influence[SgPointUtil::Col(*point)][SgPointUtil::Row(*point)] = 64;
		}
	}
	for (SgVectorIteratorOf<Region> it(board.getAllRegions(SG_WHITE)); it; ++it) {
		Region* region = *it;
		if (!board.isDead(*region)){
			SgPointSet points = region->area();
			for (SgSetIterator point(points); point; ++point)
				influence[SgPointUtil::Col(*point)][SgPointUtil::Row(*point)] = -64;
		}
	}
}

void MathBoard::dilation(){
	int tmp[SG_MAX_SIZE+1][SG_MAX_SIZE+1];
	for (int x=1; x<=SG_MAX_SIZE; ++x)
		for (int y=1; y<=SG_MAX_SIZE; ++y)
			tmp[x][y] = influence[x][y] + getDilation(InfluencePoint(x,y));
	memcpy(influence, tmp, sizeof(tmp));
}

void MathBoard::erosion(){
	int tmp[SG_MAX_SIZE+1][SG_MAX_SIZE+1];
	for (int x=1; x<=SG_MAX_SIZE; ++x)
		for (int y=1; y<=SG_MAX_SIZE; ++y)
			if (influence[x][y]>0)
				tmp[x][y] = max(influence[x][y] - getErosion(InfluencePoint(x,y)), 0);
			else if (influence[x][y]<0)
				tmp[x][y] = min(influence[x][y] + getErosion(InfluencePoint(x,y)), 0);
	memcpy(influence, tmp, sizeof(tmp));
}

int MathBoard::getDilation(InfluencePoint p){
	InfluencePointList list = getNeighbors(p);
	int sum = 0;
	for (int i=0; i<list.size; ++i){
		int value = influence[list.list[i].x][list.list[i].y];
		if  (value*sum <0)
			return 0;
		if (value!=0)
			sum+= value/abs(value);
	}
	return sum;
}

int MathBoard::getErosion(InfluencePoint p){
	InfluencePointList list = getNeighbors(p);
	int value = influence[p.x][p.y];
	int sum = 0;
	for (int i=0; i<list.size; ++i)
		sum += (value * influence[list.list[i].x][list.list[i].y] <= 0);
	return sum;
}

int MathBoard::value(){
	int value = 0;
	for (int x=1; x<=SG_MAX_SIZE; ++x)
		for (int y=1; y<=SG_MAX_SIZE; ++y)
			if (influence[x][y]<0)
				--value;
			else if(influence[x][y]>0)
				++value;
	return value;
}

void MathBoard::display(){
	SgDebug() << "Board:  " << value() << "\n";
	for (int y=SG_MAX_SIZE; y>0; --y){
		for (int x=1; x<=SG_MAX_SIZE; ++x)
			if (influence[x][y] == 0)
				SgDebug() <<  "+";
			else if (influence[x][y] > 0)
				SgDebug() << "x";
			else SgDebug() << "o";
		SgDebug() << "\n";
	}
}

InfluencePointList MathBoard::getNeighbors(InfluencePoint p){
	InfluencePointList list;
	if (p.x>1)
		list.addPoint(InfluencePoint(p.x-1, p.y));
	if (p.y>1)
		list.addPoint(InfluencePoint(p.x, p.y-1));
	if (p.x<SG_MAX_SIZE)
		list.addPoint(InfluencePoint(p.x+1, p.y));
	if (p.y<SG_MAX_SIZE)
		list.addPoint(InfluencePoint(p.x, p.y+1));
	return list;
}
